package com.dyava.dycache.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
import java.util.concurrent.Callable;

public abstract class CacheEngine {
    private final static Logger log = LoggerFactory.getLogger(CacheEngine.class);

    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //////////////////////// 需要实现
    /**
     * 获取本层缓存
     */
    protected abstract String getCacheVersion(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined, Object id);

    /**
     * 获取本层缓存
     * 返回的CacheWrap 必须不能为空！，data可以为空
     */
    protected abstract  CacheWrap getCacheWrap(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined, Object id);
    /**
     * 获取本层缓存，一直等待到都
     * 返回的CacheWrap 必须不能为空！，data可以为空
     */
    protected abstract  CacheWrap waitCacheWrap(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined, Object id);
    /**
     * 删除本层缓存
     */
    protected abstract void deleteCache(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined,Object id);
    /**
     * 保存本层缓存
     */
    protected abstract   void saveCacheWrap(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined,Object id,CacheWrap cacheWrap);

    /**
     * 调用下一层时锁定
     */
    protected abstract boolean tryLock(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined,Object id);
    /**
     * 调用下一层时解锁
     */
    protected abstract void unLock(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined, Object id);

///////////////////// 辅助函数
    /**
     * 包装数据为 CacheWrap
     */
    protected  CacheWrap wrap(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined,Object t){
        return new CacheWrap(t, generateExpireAt(cacheEngineContext,cacheDefined),generateVersion(cacheEngineContext,cacheDefined));
    };

    /**
     * 计算下一层engine
     */
    public CacheEngine nextEngine(CacheEngineContext cacheEngineContext) {
        return cacheEngineContext.nextCacheEngine(this);
    }

    /**
     * 生成版本号
     */
    protected String generateVersion(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined){
        if(cacheDefined.hasVersion){
            return UUID.randomUUID().toString().replaceAll("-","");
        }else{
            return null;
        }
    }

    /**
     * 获取缓存点在当前引擎的超时时长
     */
    protected long generateExpire(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined){
        return cacheDefined.getExpires()[cacheEngineContext.indexOf(this)];
    }

    /**
     * 获取缓存点在当前引擎的超时截止时间
     */
    protected long generateExpireAt(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined){
        return System.currentTimeMillis()+generateExpire(cacheEngineContext,cacheDefined);
    }

    /**
     * 生成key=name+id
     */
    protected String generateKey(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined,Object id){
        return cacheDefined.getName()+":"+id.toString();
    }


    /**
     * 缓存是否有效
     */
    public  boolean isCacheWrapValid(CacheEngineContext cacheEngineContext,CacheDefined cacheDefined,CacheWrap cacheWrap) {
        if(cacheWrap==null){
//            logger.debug("null 无效缓存");
            return false;
        }
        if(cacheWrap.getExpireAt() < System.currentTimeMillis()){
//            logger.debug(LocalDateTime.from(Instant.ofEpochMilli(cacheWrap.getExpireAt()).atZone(ZoneId.systemDefault())));
//            logger.debug(LocalDateTime.from(Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneId.systemDefault())));
//            logger.debug("超时无效缓存");
            return false;
        }
        return true;
    }

 ////////////////////////// 主业务
    /**
     * 链式获取
     */
    public  CacheWrap getObjectChain(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined,Object id, Callable nextGetter) {
//        logger.debug("进入 "+this+" 获取数据");
        CacheWrap cacheWrap = getCacheWrap(cacheEngineContext,cacheDefined, id);
        if(!isCacheWrapValid(cacheEngineContext,cacheDefined,cacheWrap)){ //无效缓存，包含超时和null
            log.debug("穿透-> "+ name);
            if(tryLock(cacheEngineContext,cacheDefined,id)){        //抢夺更新权,只要抢到更新权，生成的cacheWrap 就不可能为空
                log.debug("抢锁成功-> "+ name);
                cacheWrap = getCacheWrap(cacheEngineContext,cacheDefined, id);      //双锁定策略
                if(!isCacheWrapValid(cacheEngineContext,cacheDefined,cacheWrap)) {
                    CacheEngine next = nextEngine(cacheEngineContext);
                    try{
                        if(next==null){ //没有下级引擎了，开始获取原始数据
                            if(nextGetter==null){ //如果没有原始数据来源，直接返回空
                                cacheWrap = null;
                            }else{
                                Object t = null;
                                try {
                                    log.debug("读取原始数据");
                                    t = nextGetter.call();
                                    cacheWrap = wrap(cacheEngineContext,cacheDefined,t);
                                } catch (Exception e) {
                                    throw new CacheRuntimeException(e);
                                }
                            }
                        }else{      //从下级获取数据
                            cacheWrap = next.getObjectChain(cacheEngineContext,cacheDefined, id,nextGetter);
                        }
                        if(isCacheWrapValid(cacheEngineContext,cacheDefined,cacheWrap)){ //如果是有效数据，开始设置本级缓存
                            saveCacheWrap(cacheEngineContext,cacheDefined,id,cacheWrap);
                        }
                        return cacheWrap;
                    }finally {
                        unLock(cacheEngineContext,cacheDefined,id);
                    }
                }else{
                    log.debug("双锁定策略下发现正确数据-> "+name);
                    unLock(cacheEngineContext,cacheDefined,id);
                    return cacheWrap;
                }
            }else{                     //准备抢夺更新权 失败
                log.debug("抢锁失败-> "+name);
                if(cacheWrap != null){ //有超时数据，直接凑合
                    log.debug("命中-> "+name+"(超时)");
                    return cacheWrap;
                }else{                  //没有超时数据，必须持续等待到有值
                    log.debug("等待数据更新-> "+name);
                    cacheWrap = waitCacheWrap(cacheEngineContext,cacheDefined, id);
                    return cacheWrap;
                }
            }
        }else{
            log.debug("命中-> "+name);
            return cacheWrap;
        }
    }
    /**
     * 链式删除
     */
    public void deleteCacheChain(CacheEngineContext cacheEngineContext, CacheDefined cacheDefined,Object id){
        log.debug("删除-> "+name);
        deleteCache(cacheEngineContext,cacheDefined,id);
        CacheEngine next = nextEngine(cacheEngineContext);
        if(next!=null){
            next.deleteCacheChain(cacheEngineContext,cacheDefined,id);
        }
    }

}
